import styles from './styles.less'
export { styles }

export type JSONSchema = {
    $schema?: string;
    description?: string;
    mock?: string;
} & (
    {
        type: "string" | "number" | "boolean" | "integer";
    } | {
        type: "object";
        properties: Record<string, JSONSchema>;
    } | {
        type: "array";
        items: JSONSchema;
    }
)

export interface TypeField {
    name: string;
    type: string;
    description: string;
    array_depth: number;
}
export interface TypeObject {
    name: string;
    fields: TypeField[];
}

export interface TypeBuilderProps {
    schema: JSONSchema;
    /** 缩进
     * @default "    "
     */
    indent?: string;
}
const TypeBuilder = (props: TypeBuilderProps) => {
    const { schema, indent } = props
    const map = new Map<string, TypeObject>()
    const loop = function loop(schema: JSONSchema, prefix = 'Root', name = '', array_depth = 0) {
        const { type, description } = schema
        const obj = map.get(prefix)
        const InterfaceName = `${prefix}${name.replace(/\w/, t => t.toUpperCase())}`
        switch (type) {
            case 'string':
            case 'number':
            case 'integer':
            case 'boolean':
                obj.fields.push({ name, type, description, array_depth })
                break;
            case 'object':
                map.set(InterfaceName, {
                    name: InterfaceName,
                    fields: [],
                })
                Object.entries(schema.properties).forEach(([field, schema]) => loop(schema, InterfaceName, field))
                break;
            case 'array':
                switch (schema.items.type) {
                    case 'string':
                    case 'number':
                    case 'integer':
                    case 'boolean':
                        loop(schema.items, prefix, name, array_depth + 1)
                        break;
                    case 'object':
                        if (obj?.fields) {
                            obj.fields.push({
                                name,
                                type: InterfaceName,
                                description: schema.items.description,
                                array_depth: array_depth + 1,
                            })
                        }
                        loop(schema.items, prefix, name, array_depth + 1)
                        break;
                    case 'array':
                        loop(schema.items, prefix, name, array_depth + 1)
                        break;
                }
                break;
        }
    }
    loop(schema)

    return [...map.values()].map(item => stringify(item, indent)).join('\n\n')
}

export const stringify = function (obj: TypeObject, indent = '    ') {
    const lines = [`<span class="${styles.constant}">export</span> <span class="${styles.keyword}">interface</span> <span class="${styles.var}">${obj.name}</span> {`]
    for (let i = 0; i < obj.fields.length; i++) {
        const item = obj.fields[i];
        const type = item.type === 'integer' ? 'number' : item.type
        const { name, description, array_depth = 0 } = item
        description && lines.push(`${indent}<span class="${styles.comment}">/** ${description} */</span>`)
        lines.push(`${indent}${name}: <span class="${styles[type] || styles.var}">${type}</span>${'[]'.repeat(array_depth)};`)
    }
    lines.push(`}`)
    return lines.join('\n')
}

export default TypeBuilder